#include "SqlServer.h"

#ifdef DBMS_USE_SQLSERVER

#define MAXBUFLEN 255

LIBDBC_BEGIN_NAMESPACE

SQLHENV SqlServer::_hEnv = SQL_NULL_HENV;
int SqlServer::_nInstances = 0;

SqlServer::SqlServer()
{
	_hDbc = SQL_NULL_HDBC;
	if (_nInstances == 0)
	{
		_hEnv = SQL_NULL_HENV;
		SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &_hEnv);
		SQLSetEnvAttr(_hEnv, SQL_ATTR_ODBC_VERSION, (SQLPOINTER)SQL_OV_ODBC3, 0);
	}
	_hDbc = SQL_NULL_HDBC;

	_nInstances++;
}


SqlServer::~SqlServer()
{
	close();

	if (_nInstances == 0)
	{
		SQLFreeHandle(SQL_HANDLE_ENV, _hEnv);
		_hEnv = SQL_NULL_HENV;
	}
}

bool SqlServer::_connect(const char* host, const char* database, const char* user, const char* pwd, int port)
{
	bool bConnected = connect(host, user, pwd, port);
	use(database);
	return bConnected;
}

bool SqlServer::_connect(const char* host, const char* user, const char* pwd, int port)
{
	bool bOK = true;
	_storeConnectionInfo(host, user, pwd, port);

	SQLCHAR connstr[MAXBUFLEN];
	SQLCHAR connstrout[MAXBUFLEN];
	SQLSMALLINT connstrlen = 0;
	if (user && strlen(user)>0)
	{
		// System authentication
		sprintf_s((char*)connstr, MAXBUFLEN, "DRIVER=SQL Server;SERVER=%s;UID=%s;PWD=%s", host, user, pwd);
	}
	else
	{
		// windows authentication
		sprintf_s((char*)connstr, MAXBUFLEN, "DRIVER=SQL Server;SERVER=%s;Trusted_Connection=yes", host);
	}

	SQLRETURN retcode = SQL_ERROR;
	SQLRETURN allocated = SQLAllocHandle(SQL_HANDLE_DBC, _hEnv, &_hDbc);
	if ((allocated != SQL_INVALID_HANDLE) && (allocated != SQL_ERROR))
	{
		retcode = SQLDriverConnect(_hDbc, NULL, connstr, SQL_NTS, connstrout, MAXBUFLEN, &connstrlen, SQL_DRIVER_NOPROMPT /* SQL_DRIVER_PROMPT */);

		if (retcode == SQL_ERROR)
		{
			SQLSMALLINT len;
			SQLCHAR state[500];
			SQLINTEGER err;
			SQLCHAR errormsg[800];
			SQLError(_hEnv, _hDbc, NULL, state, &err, (SQLCHAR*)errormsg, 800, &len);
			_setLastError((char*)errormsg);
		}
	}

	bOK = _isSuccess(retcode);
	if (!bOK)
	{
		SQLFreeHandle(SQL_HANDLE_DBC, _hDbc);
		_hDbc = NULL;
	}

	return bOK;
}

void SqlServer::_use(const char* database)
{
	int len = static_cast<int>(strlen(database) + 20);
	_storeDatabaseName(database);
	char* query = (char*)malloc(len);
	sprintf_s(query, len, "use [%s]", database);
	_execNonQuery(query);
	free(query);
}

bool SqlServer::_createConnectedHDBC(SQLHDBC* phdbc)
{
	bool bOK = true;

	SQLCHAR connstr[MAXBUFLEN];
	SQLCHAR connstrout[MAXBUFLEN];
	SQLSMALLINT connstrlen = 0;
	if (_user && strlen(_user)>0)
	{
		// System authentication
		sprintf_s((char*)connstr, MAXBUFLEN, "DRIVER=SQL Server;SERVER=%s;UID=%s;PWD=%s", _host, _user, _pwd);
	}
	else
	{
		// windows authentication
		sprintf_s((char*)connstr, MAXBUFLEN, "DRIVER=SQL Server;SERVER=%s;Trusted_Connection=yes", _host);
	}

	SQLRETURN retcode = SQL_ERROR;
	SQLRETURN allocated = SQLAllocHandle(SQL_HANDLE_DBC, _hEnv, phdbc);
	if ((allocated != SQL_INVALID_HANDLE) && (allocated != SQL_ERROR))
	{
		retcode = SQLDriverConnect(*phdbc, NULL, connstr, SQL_NTS, connstrout, MAXBUFLEN, &connstrlen, SQL_DRIVER_NOPROMPT /* SQL_DRIVER_PROMPT */);

		if (retcode == SQL_ERROR)
		{
			SQLSMALLINT len;
			SQLCHAR state[500];
			SQLINTEGER err;
			SQLCHAR errormsg[800];
			SQLError(_hEnv, *phdbc, NULL, state, &err, (SQLCHAR*)errormsg, 800, &len);
			_setLastError((char*)errormsg);
		}
	}

	bOK = _isSuccess(retcode);
	if (!bOK)
	{
		SQLFreeHandle(SQL_HANDLE_DBC, *phdbc);
		*phdbc = NULL;
	}
	else
	{
		if (_database)
		{
			_internalSwitchDatabase(*phdbc, _database);
		}
	}
	return bOK;
}

void SqlServer::_internalSwitchDatabase(HDBC hdbc, const char* database)
{
	int len = static_cast<int>(strlen(database) + 20);
	//_storeDatabaseName(database);
	char* query = (char*)malloc(len);
	sprintf_s(query, len, "use [%s]", database);

	int result = 0;
	SQLRETURN rc;
	SQLHSTMT hstmt;         // Statement handle
	rc = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);
	rc = SQLPrepare(hstmt, (unsigned char*)query, SQL_NTS);
	rc = SQLExecute(hstmt);

	if ((rc != SQL_NO_DATA) && (_isSuccess(rc)))
		result = 1;

	SQLFreeHandle(SQL_HANDLE_STMT, hstmt);

	free(query);
}


LIBDBC_END_NAMESPACE

#endif